home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / 4cmp22s.zip / MULTID.4TH < prev    next >
Text File  |  1994-10-30  |  17KB  |  642 lines

  1. \ ForthCMP  Multitasking Module
  2. \ Copyright 1985, 1993 (C) By Thomas Almy.  All rights reserved.
  3.  
  4. \ Permission is granted to registered users of ForthCMP to sell or distribute
  5. \ computer programs incorporating the compiled contents of this file.
  6.  
  7. \ This module writes direct to the display for terminal I/O
  8.  
  9.  
  10. .( LOADING MULTID) CR
  11. FIND EMIT? [IF] DROP 1 [ELSE] 0 [THEN] CONSTANT facl  \ FACILITY Wordset used
  12. INCLUDE INTS
  13. INCLUDE FARMEM1
  14. 10 HEX
  15.  
  16. \ If EGA is defined non-zero then 43 line EGA code is generated
  17. FIND EGA [IF] DROP [ELSE] 0 CONSTANT EGA [THEN]
  18.  
  19. \ If VGA is defined non-zero then 50 line VGA code is generated
  20. FIND VGA [IF] DROP [ELSE] 0 CONSTANT VGA [THEN]
  21.  
  22. EGA 0<> VGA 0<> OR CONSTANT ENHANCED
  23.  
  24. ENHANCED [IF] 0 CONSTANT VID-DELAY [THEN]  \ no vid delay if EGA or VGA
  25. ENHANCED 0=  [IF] VARIABLE crtport  3D4 crtport ! [THEN]
  26.  
  27. \ If VID-DELAY is defined non-zero then anti-snow code is added
  28. FIND VID-DELAY [IF] DROP [ELSE] 0 CONSTANT VID-DELAY [THEN]
  29.  
  30. VARIABLE vidseg     \ VIDEO SEGMENT
  31. B800 vidseg !
  32. 50 CONSTANT c/l     \ Characters per line
  33. EGA [IF] 2B [ELSE] VGA [IF] 32 [ELSE] 19 [THEN] [THEN]
  34.    CONSTANT l/s     \ lines per screen
  35.  
  36.  
  37. DECIMAL  
  38. 0 0 IN/OUT NEED SINGLE 
  39. 0 0 IN/OUT NEED MULTI
  40. 0 0 IN/OUT NEED PAUSE
  41. 0 0 IN/OUT NEED end-timer
  42. 0 0 IN/OUT NEED start-timer
  43. 0 0 IN/OUT NEED PAGE
  44.  
  45.  
  46. VARIABLE ?multi         \ true if multitasking turned on
  47. VARIABLE user           \ disp into user segment--used at comp time
  48. VARIABLE CTASK          \ pointer to task list
  49. VARIABLE inaccept       \ executing EXPECT -- only one at a time, please!
  50.  
  51.  \ Semaphores
  52.  
  53. 1 0 IN/OUT
  54. : SEMA BEGIN DUP @ WHILE PAUSE REPEAT ON ;
  55.  
  56. 1 0 IN/OUT
  57. : PHORE  OFF PAUSE ;
  58.  
  59.  
  60. 0 0 IN/OUT 
  61. : BYE  unsetup-vid end-timer bye ;
  62.  
  63.  \ Memory management interface
  64. 1 1 IN/OUT
  65. : GET malloc IF    ." OUT OF MEMORY " BYE THEN ;
  66.  
  67.  \ USER VARIABLES 
  68. H: UALLOT  DSEG user @  +  user ! ;
  69. 1 2 IN/OUT
  70. H: UCREATE user @ CONSTANT ;
  71. H: UVARIABLE  UCREATE 2 UALLOT ;
  72. H: URESET DSEG  0 user ! ;
  73. URESET
  74.  \ redefinition of primitive I/O functions
  75. HEX
  76. 1 0 IN/OUT
  77. : storecursor ( DISPL -- )  CTASK @ 12 + CS: ! ;
  78.  
  79. 1 0 IN/OUT
  80. : setcursor (  DISPL -- )  
  81. ENHANCED [IF]
  82.     2/ DUP 0F 3D4 PC! 3D5 PC! >< 0E 3D4 PC! 3D5 PC! 
  83. [ELSE]
  84.     2/ DUP 0F crtport @ PC! crtport @ 1+ PC!
  85.     >< 0E crtport @ PC! crtport @ 1+ PC! 
  86. [THEN]
  87. ;
  88.  
  89. 0 0 IN/OUT
  90. : nocursor  l/s c/l * 2* 1- setcursor ( OFF SCREEN ! ) ;
  91.  
  92. 2 0 IN/OUT
  93. : AT-XY  c/l * + 2*  storecursor ;
  94.  
  95.  
  96. ENHANCED [IF]
  97. 0 0 IN/OUT
  98. EGA [IF]
  99. CODE set-ega
  100.     03 # AX MOV  10 INT                     \ SET MODE 3
  101.     1112 # AX MOV  0 # BL MOV  10 INT       \ Load 8X8 font
  102.     1200 # AX MOV  20 # BL MOV  10 INT      \ Load new printscreen
  103.     1 # AH MOV  707 # CX MOV  10 INT        \ LOAD CURSOR SCAN LINES
  104.     3D4 # DX MOV  0A # AL MOV  [DX] BYTE OUT \ set cursor 
  105.     FWD, THEN,
  106.     DX INC
  107.     6 # AL MOV  [DX] OUT
  108.     RET
  109. END-CODE
  110. [ELSE]  \ must be VGA
  111. CODE set-ega
  112.     1202 # AX MOV 30 # BL MOV 10 INT  \ 400 scan lines
  113.     03 # AX MOV  10 INT                     \ SET MODE 3
  114.     1112 # AX MOV  0 # BL MOV  10 INT       \ Load 8X8 font
  115.     1200 # AX MOV  20 # BL MOV  10 INT      \ Load new printscreen
  116.     RET
  117. END-CODE
  118. [THEN]
  119.  
  120. 0 0 IN/OUT
  121. CODE unset-ega
  122. VGA [IF]
  123.     1201 # AX MOV 30 # BL MOV 10 INT  \ 350 scan lines
  124. [THEN]
  125.     03 # AX MOV  10 INT  RET  END-CODE
  126. [THEN] 
  127.  
  128. 0 0 IN/OUT
  129. : setup-vid
  130. ENHANCED [IF]
  131.     set-ega
  132.     CTASK @ 12 + CS: OFF    \ home cursor
  133. [ELSE]
  134.     40 49 C@L 7 = IF 3B4 crtport ! B000 vidseg ! THEN \ MONOCHROME
  135.     40 50 C@L 40 51 C@L AT-XY
  136.     vidseg @  c/l l/s 1- * 2* 1+ C@L  CTASK @ 14 + CS: ! 
  137. [THEN]
  138. ;
  139.  
  140.  CODE unsetup-vid  
  141. ENHANCED [IF]
  142.     CALL' PAGE
  143.     CALL' unset-ega
  144.     DX DX XOR
  145. [ELSE]
  146.     CTASK [] BX MOV
  147.     CS: 12 +[BX] AX MOV  \ cursor offset
  148.     c/l # BX MOV 
  149.     DX DX XOR
  150.     AX 1 SAR  
  151.     BX IDIV
  152.     AL DH MOV  
  153. [THEN]
  154.     2 # AH MOV 
  155.     BH BH XOR  
  156.     10 INT  
  157.     RET 
  158. END-CODE \ unsetup-vid
  159.  
  160. CODE scrmove  ( source dest wordCount -- )
  161.     BX POP 
  162.     CX POP
  163.     DI POP
  164.     SI POP
  165.     LOOP IF,
  166.         DS PUSHSEG
  167. VID-DELAY [IF]  
  168.         B800 # vidseg [] CMP  =0 IF,
  169.             3DA # DX MOV
  170.             BEGIN,  
  171.                 BYTE [DX] IN  
  172.                 8 # AL TEST  
  173.             =0 ~ UNTIL,
  174.             DX DEC
  175.             DX DEC
  176.             21 # AL MOV
  177.             BYTE [DX] OUT
  178.         THEN, 
  179. [THEN]
  180.         vidseg [] AX MOV
  181.         AX DS >SEG
  182.         AX ES >SEG
  183.         REPZ MOVS
  184.         DS POPSEG
  185. VID-DELAY [IF]
  186.         B800 # vidseg [] CMP  =0 IF,
  187.             3D8 # DX MOV
  188.             29 # AL MOV
  189.             BYTE [DX] OUT
  190.         THEN, 
  191. [THEN]
  192.     THEN, 
  193.     BX JMPI 
  194. END-CODE \ scrmove
  195.  
  196. 2 0 IN/OUT
  197. CODE scrfill ( source wordCount -- )
  198.     vidseg [] ES >SEG
  199.     20 # BYTE ES: [BX] MOV
  200.     CTASK [] DI MOV
  201.     CS: 14 +[DI] CL MOV  \ style
  202.     CL ES: 1 +[BX] MOV
  203.     BX PUSH
  204.     BX INC 
  205.     BX INC 
  206.     BX PUSH  
  207.     AX DEC 
  208.     AX PUSH
  209.     CALL' scrmove
  210.     RET
  211. END-CODE \ scrfill
  212.  
  213. 0 0 IN/OUT
  214. : scrollup  c/l 2*  0  c/l l/s 1- * scrmove
  215.     c/l l/s 1- * 2*  c/l    scrfill
  216.     c/l l/s 1- * 2*  CTASK @ 12 + CS: ! ( set cursor ) ;
  217.  
  218. 0 2 IN/OUT
  219. : ?XY     CTASK @ 12 + CS: @  2/  0 c/l UM/MOD ;
  220.  
  221. 1 0 IN/OUT
  222. : FOREGROUND 0F AND CTASK @ 14 + TUCK CS: @ F0 AND OR SWAP CS: ! ;
  223.  
  224. 1 0 IN/OUT
  225. : BACKGROUND 7 AND 4 LSHIFT CTASK @ 14 + TUCK CS: @ 0F AND OR SWAP CS: ! ;
  226.  
  227.  
  228. : EMIT  
  229.     CTASK @ 12 + CS: @  c/l l/s * 2* >= IF scrollup THEN
  230.     vidseg @ CTASK @ 12 + CS: @ C!L
  231.     CTASK @ 14 + CS: @ vidseg @ CTASK @ 12 + CS: @ 1+ C!L
  232.     CTASK @ 12 + CS: @ CELL+ storecursor  PAUSE ;
  233.  
  234. : CR
  235.     CTASK @ 12 + CS: @  
  236.     c/l 2*  U/  1+  c/l 2*  *
  237.     DUP c/l l/s * 2* = IF DROP scrollup  CTASK @ 12 + CS: @ THEN
  238.     storecursor  PAUSE ;
  239.  
  240. : SPACES
  241.     DUP 0> IF
  242.         c/l l/s * 2*  CTASK @ 12 + CS: @ - OVER 2* < IF ( too big )
  243.         0 DO BL EMIT LOOP ELSE
  244.             CTASK @ 12 + CS: @  SWAP 2DUP scrfill
  245.         2* + storecursor  PAUSE 
  246.         THEN 
  247.     ELSE   DROP
  248.     THEN
  249. ;
  250.  
  251.  
  252. 2 1 IN/OUT
  253. CODE (type) ( AX has count, BX has string, result is cursor position )
  254.     BX SI MOV
  255.     CTASK [] BX MOV
  256.     CS: 12 +[BX] DI MOV \ cursor
  257.     AX CX MOV
  258.     CS: 14 +[BX] AH MOV \ style
  259.     vidseg [] ES >SEG
  260.     LOOP IF, 
  261.         BEGIN,
  262.             BYTE LODS
  263.             STOS  
  264.         LOOP ~ UNTIL,
  265.     THEN,
  266.     DI AX MOV       \ final cursor position
  267.     RET
  268. END-CODE \ (type)
  269.  
  270. : TYPE 
  271.     c/l l/s * 2*  CTASK @ 12 + CS: @ - OVER 2* < IF ( too big )
  272.         0 ?DO COUNT EMIT LOOP DROP
  273.     ELSE 
  274.         (type) storecursor PAUSE 
  275.     THEN ;
  276.  
  277. 2 1 IN/OUT
  278. CODE (cs:type) ( AX has count, BX has string, result is cursor position)
  279.     BX SI MOV
  280.     CTASK [] BX MOV
  281.     CS: 12 +[BX] DI MOV \ cursor
  282.     AX CX MOV
  283.     CS: 14 +[BX] AH MOV \ style
  284.     vidseg [] ES >SEG
  285.     LOOP IF, 
  286.         BEGIN,
  287.             CS: BYTE LODS
  288.             STOS  
  289.         LOOP ~ UNTIL,
  290.     THEN,
  291.     DI AX MOV       \ final cursor position
  292.     RET
  293. END-CODE \ (cs:type)
  294.  
  295. : CS:TYPE 
  296.     c/l l/s * 2* CTASK @ 12 + CS: @ - OVER 2* < IF ( too big )
  297.         0 ?DO CS: COUNT EMIT LOOP DROP
  298.     ELSE 
  299.         (cs:type) storecursor PAUSE 
  300.     THEN ;
  301.  
  302.  
  303. 0 0 IN/OUT 
  304. : PAGE  0  c/l l/s *  scrfill  0 storecursor ;
  305.  
  306. 0 1 IN/OUT
  307. facl [IF]
  308. CODE EKEY?
  309. [ELSE]
  310. CODE KEY?
  311. [THEN]
  312.     CALL' PAUSE     \ allow another task to execute
  313.     1 # AH MOV 
  314.     16 INT 
  315.     0 # AX MOV
  316.     =0 ~ IF, AX DEC  THEN,
  317.     RET
  318. END-CODE \ KEY?
  319.  
  320. : PAD CTASK @ 18 + CS: @ ;
  321.  
  322.  
  323. facl [IF]
  324. VARIABLE pchr -1 pchr !
  325. : KEY  pchr @ 0< 0= IF pchr @ pchr ON EXIT THEN
  326.   BEGIN EKEY EKEY>CHAR 0= WHILE DROP REPEAT ;
  327. : KEY? pchr @ 0< 0= IF TRUE EXIT THEN
  328.   BEGIN EKEY? CTASK @ 12 + CS: @ setcursor WHILE 
  329.         EKEY EKEY>CHAR IF pchr ! TRUE EXIT THEN DROP 
  330.   REPEAT FALSE ;
  331. : EKEY BEGIN EKEY? CTASK @ 12 + CS: @ setcursor UNTIL 0 7 BDOS 
  332.       ?DUP 0= IF BEGIN EKEY? CTASK @ 12 + CS: @ setcursor UNTIL  
  333.               0 7 BDOS 256 + THEN ;
  334. [ELSE]
  335. : KEY  BEGIN KEY?  CTASK @ 12 + CS: @ setcursor UNTIL  
  336.     0 8 BDOS 
  337.     PAUSE
  338.     nocursor ;
  339. [THEN]
  340.  
  341.  \ ACCEPT
  342.  
  343. 0 0 IN/OUT
  344. : bu  CTASK @ 12 + CS: @ CELL- DUP storecursor BL EMIT storecursor ;
  345.  
  346. DECIMAL
  347.  
  348. : ACCEPT
  349.     inaccept SEMA       \ too hard if two or more tasks want input at once!
  350.     >R 0
  351.     BEGIN
  352.         KEY  CASE
  353.         [CTRL] [ OF 0 ?DO  bu LOOP 0 ENDOF
  354.         [CTRL] H OF DUP IF bu 1- THEN ENDOF
  355.         [CTRL] M OF 
  356.             NIP R> DROP 
  357.             inaccept PHORE 
  358.             EXIT ENDOF
  359.         ( ELSE ) OVER R@ <> IF DUP >R EMIT
  360.             2DUP + R> SWAP C! 1+ 0 THEN
  361.         ENDCASE
  362.     AGAIN ;
  363.  
  364.  
  365.  \ TASK CREATION 
  366. HEX
  367. H: TASK                          \ values after INIT-TASKS:
  368.    CSEG CREATE HERE E92E ,    \ DISP 0 -- JMP ( task asleep )
  369.    DSEG CTASK @ ,  CTASK !    \     02 -- relative addr nxt task
  370.    user @ ,                   \     04 -- size of user area (not used?)
  371.    0 ,                        \     06 -- SS register contents
  372.    user @ pssize 10 * + ,     \     08 -- SP register contents
  373.    user @ pssize 10 * + rssize + , \     0A -- BP register contents
  374.    ,                          \     0C -- PC contents
  375. \ the following fields are for per-task variables
  376. \ and could be selectively elimiated if not needed if space is 
  377. \ at a premium.  In that case, offsets may need to be adjusted
  378. \ for words which use latter fields.
  379.    0 ,                        \     0E -- Message list
  380.    0 ,                        \     10 -- Timer
  381.    0 ,                        \     12 -- Cursor location
  382.    7 ,                        \     14 -- character attribute (style)
  383.    0 ,                        \     16 -- Exception frame pointer
  384.    DSEG HERE 80 ALLOT 22 + ,  \     18 -- PAD, a per-task work area
  385. 0 [IF]
  386. Initially, DISP 2 has absolute address of next task.
  387. This values as well as DISP 6 get
  388. filled in by INIT-TASKS when application is run.
  389. [THEN]
  390.  
  391. CSEG  CREATE MAIN-TASK  \ Give it a name
  392. HERE DSEG CTASK !             \ Task list points to it
  393. 80CD ,                          \ DISP 0 -- INT 80 (task awake)
  394.    0 ,                          \ 02 -- relative addr next task
  395.    0 ,                          \ 04 -- NOT USED
  396.    0 ,                          \ 06 -- SS register contents
  397.    0 ,                          \ 08 -- SP register contents
  398.    0 ,                          \ 0A -- BP register contents
  399.    0 ,                          \ 0C -- PC contents
  400.    0 ,                          \ 0E -- Message list
  401.    0 ,                          \ 10 -- Timer
  402.    0 ,                          \ 12 -- Cursor Location
  403.    7 ,                          \ 14 -- Style
  404.    0 ,                          \ 16 -- Exception Frame Pointer
  405.    DSEG HERE 80 ALLOT 22 + ,    \ 16 -- PAD, a per-task work area
  406. 0 [IF]
  407. DISP-2, 6, and 12 get filled in by INIT-TASK.  -8 -0A and -0C
  408. are filled by first task swap (which is done by INIT-TASK).
  409. [THEN]
  410.  
  411.  \ TASK INITIALIZATION
  412. 0 0 IN/OUT 
  413. : INIT-TASKS \ This MUST be executed to start multitasking
  414.     CTASK @
  415.     BEGIN ?DUP WHILE  \ for each task DO:
  416.         CELL+ DUP CS: @ IF  \ one follows, this isn't main task
  417.             DUP 8 + CS: @ 10 + 4 RSHIFT  GET 
  418.          OVER 4 + CS: ! \ stackseg
  419.             DUP CS: @ TUCK   \ next task
  420.         ELSE
  421.             0 SWAP CTASK @ \ next task is head of list
  422.         THEN
  423.         OVER - CELL- SWAP CS: !  
  424.     REPEAT
  425.     MAIN-TASK CTASK !  
  426.     setup-vid
  427.     ?SS: MAIN-TASK 6 + CS: !    \ sets main task stack segment
  428.     start-timer
  429.     MULTI ( GO!!! ) ;
  430.  
  431.  \ TASK DISPATCHER
  432. CODE PAUSE  
  433.     0 # ?multi [] CMP  
  434.     =0 IF, RET THEN,
  435.     CTASK [] BX MOV         \ current task
  436.     CS: 0C +[BX] POP        \ save PC
  437.     BP CS: 0A +[BX] MOV     \ save BP
  438.     SP CS: 08 +[BX] MOV     \ save SP
  439.     CS: 2 +[BX] BX ADD  
  440.     4 # BX ADD  
  441.     CLI                \ no ints during dispatch!
  442.     BX JMPI  ( dispatch )
  443. END-CODE \ PAUSE
  444.  
  445. 0 [IF]
  446. Tasks are linked together so that jumping to a task will cause
  447. jumping to the next if it is asleep, or doing an INT 80 if it
  448. is awake.  Thanks to Henry Laxen's Forth 83 model for the
  449. technique.
  450. [THEN]
  451.  
  452. L: start-task ( the INT80 routine )  
  453.     BX POP 
  454.     BX DEC 
  455.     BX DEC                  \ Pointer to the task
  456.     CS: 6 +[BX] SS >SEG     \ restore stack segment
  457.     CS: 8 +[BX] SP MOV      \ restore SP
  458.     STI                     \ Interrupts are safe now
  459.     CS: 0A +[BX] BP MOV     \ restore BP
  460.     BX  CTASK [] MOV        \ current task
  461.     CS: 0C +[BX] JMPI       \ go!
  462. FORTH \ start-task 
  463. 0 [IF]
  464. This code starts up a new task by setting up all registers,
  465. fixing CTASK and USERP, and jumping to where we left off.
  466. [THEN]
  467.  
  468.  \ TASK MANAGEMENT
  469. : SINGLE  ?multi OFF ;
  470.  
  471. : MULTI   ?multi ON
  472.     ?CS: start-task 80 set-handler  \ install interrupt vector
  473.     PAUSE  \ start with a task swap
  474. ;
  475.  
  476. 1 0 IN/OUT
  477. : WAKE  80CD CS: <- ;
  478.  
  479. 1 0 IN/OUT
  480. \ the 2e prefix byte (CS override) makes the jmp instruction 4 bytes long
  481. : SLEEP (  task -- )   E92E CS: <- ;
  482.  
  483. 1 1 IN/OUT
  484. : WAITING?  10 + CS: @ 0<> ;
  485.  
  486. 0 0 IN/OUT
  487. : STOP  CTASK @ SLEEP PAUSE ;
  488.  
  489. 0 1 IN/OUT
  490. : ACTIVE-TASKS
  491.     0 MAIN-TASK
  492.     BEGIN
  493.         DUP WAITING? IF SWAP 1+ SWAP ELSE 
  494.             DUP CS: @ 80CD = IF SWAP 1+ SWAP THEN THEN \ check for active
  495.         DUP CELL+ CS: @ + 4 + \ address of next task
  496.     DUP MAIN-TASK = UNTIL     \ Loop until back to start
  497.     DROP ( task address )
  498. ;
  499.  
  500.  \ MESSAGE PASSING
  501. 0 1 IN/OUT
  502. : MESSAGE?  CTASK @ 0E + CS: @ ;
  503.  
  504. 0 1 IN/OUT
  505. : GET-MESSAGE  
  506.   BEGIN MESSAGE? ?DUP 0= WHILE STOP REPEAT
  507.   DUP  0 @L  CTASK @ 0E + CS: !  \ Unlink message
  508. ;   
  509.  
  510. 1 1 IN/OUT
  511. : MESSAGES 
  512.     0 SWAP 0E + CS: @ ?DUP IF
  513.         BEGIN SWAP 1+ SWAP  0 @L  ?DUP 0= UNTIL
  514.     THEN ;
  515.  
  516. 2 0 IN/OUT
  517. : SEND-MESSAGE 
  518.     OVER 0 SWAP 0 !L        \ set message's next field to NIL
  519.     DUP WAITING? 0= IF DUP WAKE THEN \ fire up receiving task
  520.                                 \ unless waiting for timer
  521.     0E + DUP CS: @ ?DUP IF  \ Existing messages in queue
  522.         NIP
  523.         BEGIN DUP 0 @L ?DUP WHILE NIP REPEAT \ find end of list
  524.         0 !L  \ store message at end of list
  525.     ELSE
  526.         CS: !     \ no existing messages, put at head of queue.
  527.     THEN
  528.     PAUSE ;  \ Give it a chance to run
  529.  
  530.  \ control-break handler
  531. \ always gets control and (currently) dumps task information
  532.  
  533. 2VARIABLE cb_save
  534.  
  535. 1B CONSTANT cb_int
  536.  
  537. 0 0 IN/OUT
  538. : cbt  
  539.     PAGE 
  540.     SINGLE
  541.     end-timer
  542.     ." Task statistics: "
  543.     MAIN-TASK \ start with first
  544.     BEGIN CR
  545.         HEX DUP 0 <# # # # # #> TYPE SPACE \ address
  546.         DUP WAITING? IF ." Waiting " DUP 10 + CS: @ . ." ticks" ELSE 
  547.             DUP CS: @ 80CD = IF ." Active" ELSE ." Sleeping" THEN THEN 
  548.         DUP CELL+ CS: @ + 4 + \ address of next task
  549.     DUP MAIN-TASK = UNTIL     \ Loop until back to start
  550.     DROP ( task address )
  551. EGA [IF]
  552.     CR ." Hit any key when finished"    KEY DROP
  553. [THEN]
  554.     unsetup-vid
  555.     bye
  556. ;
  557.  
  558.  
  559. ' cbt TASK cb-task
  560.  
  561.  
  562. L: cb_handler ( actual interrupt handler )
  563.       80CD # CS: cb-task [] MOV \ wake cb task
  564.     STI
  565.     IRET FORTH
  566.  
  567.  
  568.  \ timer
  569. 1C CONSTANT t_int               \ timer interupt vector number
  570. CSEG 
  571. CREATE t_save 4 ALLOT           \ original interupt vector
  572. L: t_handler
  573.     PUSHF CS: t_save CALLF    \ do original functions
  574.     BX PUSH
  575.     MAIN-TASK # BX MOV ( start of list )
  576.     BEGIN,  
  577.         CS: 0 # 10 +[BX] CMP =0 ~ IF, ( non_zero time )
  578.             CS: 10 +[BX] DEC  ( count down )
  579.             =0 IF, 80CD # CS: [BX] MOV THEN, ( wake task )
  580.         THEN,
  581.         CS: 2 +[BX] BX ADD 
  582.         4 # BX ADD ( next task )
  583.         MAIN-TASK # BX CMP  
  584.     =0 UNTIL, ( back at start? )
  585.     BX POP 
  586.     IRET
  587. FORTH \ t_handler
  588.  
  589. \ timer start and end                          08:09 11/18/85
  590.  
  591. : start-timer  \ and control break handler
  592.     t_int get-handler  t_save CS: 2!
  593.     ?CS: t_handler t_int set-handler
  594.     cb_int get-handler cb_save 2!
  595.     ?CS: cb_handler cb_int set-handler
  596. ;
  597.  
  598. : end-timer
  599.     t_save CS: 2@  t_int set-handler
  600.     cb_save 2@ cb_int set-handler
  601. ;
  602.  
  603. 2 0 IN/OUT
  604. : TIME-OUT ( ticks task -- )  DUP SLEEP 10 + CS: ! ;
  605.  
  606. 1 0 IN/OUT
  607. DECIMAL
  608. : MS ( ticks -- ) 182 10000 */ CTASK @ TIME-OUT PAUSE ;
  609. HEX
  610.  \ Exception Wordset
  611.  
  612. CODE CATCH 
  613.   SI POP  AX POP  \ retAddr execAddr
  614.   CTASK [] BX MOV
  615.   BP DEC BP DEC SI [BP] MOV
  616.   BP DEC BP DEC SP [BP] MOV
  617.   BP DEC BP DEC CS: 16 +[BX] CX MOV  CX [BP] MOV
  618.   BP CS: 16 +[BX] MOV
  619.   AX CALLI
  620.   [BP] AX MOV  AX CS: 16 +[BX] MOV  
  621.   AX AX XOR  AX PUSH
  622.   4 +[BP] AX MOV  6 # BP ADD  
  623.   AX JMPI
  624. END-CODE
  625.  
  626. 1 0 IN/OUT
  627. CODE throw
  628.   CTASK [] BX MOV
  629.   CS: 16 +[BX] BP MOV [BP] BX MOV BX CS: 16 +[BX] MOV
  630.   2 +[BP] SP MOV  AX PUSH
  631.   4 +[BP] AX MOV
  632.   6 # BP ADD  AX JMPI
  633. END-CODE
  634.  
  635. : THROW  ?DUP IF CTASK @ 16 + CS: @ IF throw THEN
  636.        ." Uncaught THROW: " . BYE THEN ;
  637.  
  638.  
  639.  
  640. DSEG 0A = [IF] DECIMAL [THEN]
  641.